#include "AnimationData.hpp"

namespace se {
namespace Graphics {
///////////////////////////////////////////////////////////////////////////////
/// \brief Load the default animation.
/// 
/// Ideally a big ugly rose "thing"
///////////////////////////////////////////////////////////////////////////////
AnimationData::AnimationData() :
	ID("none"),
	m_dataIsLoaded(true),
	m_dataContentFile(NULL),
	m_dataRef(0),
	m_sourceImg(),
	m_nFrames(1),
	m_frameTime(1){
	sf::Image i;
	i.create(100,100, sf::Color(255, 20, 147,255));// Ugly rose
	m_sourceImg.loadFromImage(i);
}

///////////////////////////////////////////////////////////////////////////////
/// \brief Load an animation using a file.
/// 
/// The file must have the following content in this order
/// - uint 2 frame count
/// - uint 2 time of a frame(ms)
/// \note The heavy data won't be loaded imediately, and will
/// wait for a call to LoadData() to be in memory.
/// @param c The ContentFile to load from.
/// @param contentRef The reference of the AnimationDataFile in the container.
///////////////////////////////////////////////////////////////////////////////
AnimationData::AnimationData(ContentFile &c, uint32_t contentRef) :
	ID(),
	m_dataIsLoaded(false),
	m_dataContentFile(&c),
	m_dataRef(),
	m_sourceImg(),
	m_nFrames(),
	m_frameTime()
{
	uint32_t imageRef;
	DataFile animFile;
	c.Get(animFile, contentRef);
	animFile.Read(&m_nFrames,2);
	animFile.Read(&m_frameTime,2);
	animFile.Read(&imageRef,4);
	ID = animFile.GetString();
	m_dataRef = imageRef;
	LoadData();
}

///////////////////////////////////////////////////////////////////////////////
/// \brief Create a animation using directly the data.
///
/// Please note that the heavy data won't be loaded imediately, and will
/// wait for a call to LoadData() to be in memory.
/// @param nFrames The number of frames in the animation. Should be dividing the image witdh.
/// @param frameTime The time for one frame to to be displayed. In milliseconds.
/// @param imageRef The reference of the image containing the animation in c.
/// @param c The ContentFile to load from.
/// @param s The animation ID string.
///////////////////////////////////////////////////////////////////////////////
AnimationData::AnimationData(uint16_t nFrames,uint16_t frameTime,uint32_t imageRef, ContentFile &c, const std::string s) :
	ID(s),
	m_dataIsLoaded(false),
	m_dataContentFile(&c),
	m_dataRef(imageRef),
	m_sourceImg(),
	m_nFrames(nFrames),
	m_frameTime(frameTime)
{LoadData();}

///////////////////////////////////////////////////////////////////////////////
/// \brief Tells if the data have been loaded.
///
/// The image from where the frames are extracted is not always loaded at
/// startup, to allow dynamical loading of data when needed.
/// @return true if the Animation is ready to be used, false if it needs loading first.
/// @see AnimationData::LoadData()
/// @see AnimationData::UnloadData()
///////////////////////////////////////////////////////////////////////////////
bool AnimationData::GetDataIsLoaded(){
	return m_dataIsLoaded;
}

///////////////////////////////////////////////////////////////////////////////
/// \brief Load the data if it hasn't already been.
///
/// TODO: Thread the data loading : opening a file takes time. Something like a LoadTread ?
/// @see AnimationData::GetDataIsLoaded() for more info.
/// @see AnimationData::UnloadData()
///////////////////////////////////////////////////////////////////////////////
void AnimationData::LoadData(){
	if(!m_dataIsLoaded){
		DataFile image;
		m_dataContentFile->Get(image,m_dataRef);
		m_sourceImg.loadFromMemory(image.GetContentPtr(), (size_t)image.GetSize());
		
		m_dataIsLoaded = true;
	}
}

///////////////////////////////////////////////////////////////////////////////
/// \brief Unload the data if it is loaded.
///
/// @see AnimationData::GetDataIsLoaded() for more info.
/// @see AnimationData::LoadData()
///////////////////////////////////////////////////////////////////////////////
void AnimationData::UnloadData(){
	if(m_dataIsLoaded){
		m_dataIsLoaded = false;
	}
}

///////////////////////////////////////////////////////////////////////////////
/// \brief Returns a reference to the source image of the animation.
///////////////////////////////////////////////////////////////////////////////
const sf::Texture& AnimationData::GetSourceImage(){
	return m_sourceImg;
}

///////////////////////////////////////////////////////////////////////////////
/// \brief Gets a frame to display using a se::Sprite.
///
/// This method gets the m_chono of the sprite to get the frame it should be
/// displaying.
/// @param sprite The sprite to use.
///////////////////////////////////////////////////////////////////////////////
uint16_t AnimationData::GetFrame(Time_t t) {
	return (t/m_frameTime)%m_nFrames;
}

///////////////////////////////////////////////////////////////////////////////
/// \brief Gets the subrect corresponding to the frame.
///
/// This method use the source image width and the total number of frames to
/// get the correct subrect of the source image that should be displayed at a
/// given frame.
/// @param frame The frame to use.
///////////////////////////////////////////////////////////////////////////////
sf::Rect<int> AnimationData::GetSubrectFromFrame(uint16_t frame) {
	sf::Rect<int> ret;
	
	ret.left = (m_sourceImg.getSize().x*frame)/m_nFrames;
	ret.width = m_sourceImg.getSize().x/m_nFrames;
	ret.top = 0;
	ret.height = m_sourceImg.getSize().y;
	return ret;
}
///////////////////////////////////////////////////////////////////////////////
/// \brief Gets the subrect corresponding to the current time.
///
/// This method use the source image width and the total number of frames to
/// get the correct subrect of the source image that should be displayed at a
/// given time.
/// @param t The time to use.
///////////////////////////////////////////////////////////////////////////////
sf::Rect<int> AnimationData::GetSubrectFromTime( Time_t t){
	return GetSubrectFromFrame(GetFrame(t));
}

///////////////////////////////////////////////////////////////////////////////
/// \brief Gets the total loop time.
///
/// ie the time to go through the whole animation.
///////////////////////////////////////////////////////////////////////////////
se::Time_t AnimationData::GetLoopTime() {
	return m_frameTime * m_nFrames;
}

///////////////////////////////////////////////////////////////////////////////
/// \brief Destructor.
///
///////////////////////////////////////////////////////////////////////////////
AnimationData::~AnimationData(){
	//nothing to do here, the image will be freed automatically
}

}//</namespace Graphics>
}//</namespace se>
